#include "StdAfx.h"

#define MYLIB_API_EXPORT
#include "GeneralizationAPI.h"
#include "MeshSimplification.h"
#include "MorphologicalProc.h"
#include "KernelConverter.h"

CGeneralizationAPI::CGeneralizationAPI(void)
{
}


CGeneralizationAPI::~CGeneralizationAPI(void)
{
}

#define TESTOBJPATH "test"
void CGeneralizationAPI::myObj2Off(bool mode)
{
	Parser_obj* parser = Parser_obj::GetSingleton();
	while(1)
	{
		if (mode)
		{
			char inname[50], outname[50];
			std::cout<<"input name (obj to off)"<<std::endl;
			std::cin>>inname;

			std::string str_inname = (inname);

			ModelOBJ* test = new ModelOBJ;
			SOLID_itr sd_itr = test->begin();
			parser->read_model_obj(("d:\\" + str_inname + ".obj").c_str(), ("d:\\" + str_inname + ".mtl").c_str(),test);
			parser->convert_to_off(*sd_itr,("d:\\" + str_inname + ".off").c_str());

			delete test;
			test = NULL;

		}
		else
		{
			char inname[50], outname[50];
			std::cout<<"input name (off to obj)"<<std::endl;
			std::cin>>inname;

			std::string str_inname = (inname);

			parser->convert_off_to_obj(("d:\\" + str_inname + ".off").c_str(),("d:\\" + str_inname + ".obj").c_str());
		}
		parser->init();
	}
}

void CGeneralizationAPI::varycolor(Parser_obj* parser)
{
	char name1[100];
	std::cout<<"objname"<<std::endl;
	std::cin>>name1;
	char name2[100];
	std::cout<<"clrname"<<std::endl;
	std::cin>>name2;
	material_prop myMtl(25.0, 1.5, 1.0, 0.0, 1.0, 1.0, 1.0, 0.3, 0.3, 0.3, 2);//common properties
	std::string pathname(TESTOBJPATH);
	std::string objname(name1);
	objname = pathname + objname;
	std::string clrname = pathname+"cottoncandy.clr";
	parser->vary_mtl_for_obj(objname.c_str(),clrname.c_str(),myMtl);
}

void CGeneralizationAPI::myModelValidation()
{
	Parser_obj* parser = Parser_obj::GetSingleton();
	while(1){
		ModelOBJ* test = new ModelOBJ;
		char inname[50];
		std::cout<<"input name (validation)"<<std::endl;
		std::cin>>inname;

		std::string str_inname = (inname);

		SOLID_itr sd_itr = test->begin();
		parser->read_model_obj(("d:\\" + str_inname + ".obj").c_str(), ("d:\\" + str_inname + ".mtl").c_str(),test,true);
		parser->write_obj(("d:\\" + str_inname + "_log2.obj").c_str(),test,true);
		delete test;
		test = NULL;
		parser->init();
	}
}

void CGeneralizationAPI::simplification_model()
{
	char name[20];
	std::cout<<"name"<<std::endl;
	std::cin>>name;
	float ratio = 0;
	std::cout<<"ratio(percentage):"<<std::endl;
	std::cin>>ratio;
	ModelOBJ* myModel = new ModelOBJ;
	Parser_obj* parser = Parser_obj::GetSingleton();
	std::string objname(TESTOBJPATH);
	objname += name;
	std::string mtlname = objname + ".mtl";
	objname += ".obj";//Objname
	parser->read_model_obj(objname.c_str(),mtlname.c_str(),myModel);
	int res = Simplify_func::GetSingleton()->Simplification_Halfedge(myModel,ratio/100);
	std::string test2 = objname;
	std::string::size_type idx = test2.rfind('.');
	std::string tmpname = test2.substr(0,idx);
	tmpname += "_simp";
	char tmp[20];
	_itoa(ratio,tmp,10);
	tmpname += std::string(tmp);
	tmpname += ".obj";
	parser->write_obj(tmpname.c_str(),myModel);
	delete myModel;
	myModel = NULL;
}

ModelOBJ* CGeneralizationAPI::do_generalization(ModelOBJ* myModel, std::string objname, float size, int bType, float fTol)
{
	// generalization
	std::cout<<"-------------"<<objname<<"@"<<size<<"--------------"<<std::endl
		<<"Connectivity Extraction begins.."<<std::endl<<"---------------------------"<<std::endl;
	CompGraph::GetSingleton()->build_graph(myModel,size,bType,fTol);//myModel has been freed
	std::cout<<"-------------"<<objname<<"@"<<size<<"--------------"<<std::endl
		<<"Connectivity Extraction ends"<<std::endl<<"---------------------------"<<std::endl;

	if (CompGraph::GetSingleton()->el.size() != 0)
	{
		//
		std::cout<<"-------------"<<objname<<"@"<<size<<"--------------"<<std::endl
			<<"Combining Polyhedron..."<<std::endl<<"---------------------------"<<std::endl;
		bool bIsCombined = CompGraph::GetSingleton()->combine_polys();

		std::cout<<"-------------"<<objname<<"@"<<size<<"--------------"<<std::endl
			<<"Prepare to output..."<<std::endl<<"---------------------------"<<std::endl;
		ModelOBJ* resultModel = new ModelOBJ;
		CompGraph::EdgeList::iterator ei = CompGraph::GetSingleton()->el.begin();
		int iObj = 0;//the name ID of the objects
		while(ei != CompGraph::GetSingleton()->el.end())
		{
			std::cout<<iObj<<std::endl;
			CompGraph::Edge* e = *ei++;
			//wadang
			if (bType == 0)
			{
				e->first = CMorphologicalProc::GetSingleton()->ReversMinKowskisum(e->first,size);
			}
			//post process if combined then closing the neighbor
			if (bIsCombined)
			{
				//e->first = MinKowskisum(e->first,-fTol);
				//e->first = ReversMinKowskisum(e->first,-fTol);
			}
			//
			if (e->first->is_simple())
			{
				//Kerneal conversion EK to IK
				EK_Poly_3 ek_ply;
				e->first->convert_to_polyhedron(ek_ply);
				SolidOBJ* solid = new SolidOBJ;
				if (!CKernelConverter::GetSingleton()->EK_to_IK(&ek_ply,solid->Solid_mesh))
				{
					return NULL;
				}
				//delete poly
				delete e->first;
				e->first = NULL;
				//
				std::stringstream objName;
				objName<<iObj++;
				solid->Solid_name = objName.str();
				//
				resultModel->push_back(solid);
			}
		}
		//
		return resultModel;
	}
	return NULL;
}

Polyhedron_3* CGeneralizationAPI::do_aggregation(ModelOBJ* myModel)
{
	std::cout<<"aggregate all the models"<<std::endl;
	SOLID_itr solid_itr = myModel->begin();
	SolidOBJ* firstSolid = *solid_itr++;
	if (!firstSolid || !firstSolid->Solid_mesh)
	{
		return NULL;
	}

	//Kernel conversion IK to EK
	EK_Poly_3 ek_poly;
	if (!CKernelConverter::GetSingleton()->IK_to_EK(firstSolid->Solid_mesh,&ek_poly))
	{
		return NULL;
	}
	Nef_polyhedron_3* result = new Nef_polyhedron_3(ek_poly);
	//
	while(solid_itr != myModel->end())
	{
		SolidOBJ* curSolid = *solid_itr++;
		if (!curSolid || !curSolid->Solid_mesh)
		{
			std::cerr<<"solid is invalidate"<<std::endl;
			return NULL;
		}
		if (curSolid->Solid_mesh->size_of_facets()==0)
		{
			continue;
		}
		//Kernel conversion IK to EK
		EK_Poly_3 ek_poly;
		if (!CKernelConverter::GetSingleton()->IK_to_EK(curSolid->Solid_mesh,&ek_poly))
		{
			return NULL;
		}
		Nef_polyhedron_3* tempres = new Nef_polyhedron_3(ek_poly);
		//closing
		*result = *result + *tempres;
		delete tempres;
		tempres = NULL;
	}
	//
	Polyhedron_3* poly = new Polyhedron_3;
	if (result->is_simple())
	{
		//Kernel conversion EK to IK
		EK_Poly_3 ek_poly;
		result->convert_to_polyhedron(ek_poly);
		if (!CKernelConverter::GetSingleton()->EK_to_IK(&ek_poly,poly))
		{
			return NULL;
		}
		delete result;
		result = NULL;
		return poly;
	}
	else
	{
		std::cerr<<"result is not closed"<<std::endl;
		delete result;
		result = NULL;
		return NULL;
	}
	return NULL;
}

bool CGeneralizationAPI::do_post_proc(ModelOBJ* myModel, float size, int iFlag /* = 1 */)
{
	if (myModel)
	{
		if (0 == iFlag)
		{//just closing
			CMorphologicalProc::GetSingleton()->minkowski_closing(myModel,size);
		}
		else if (1 == iFlag)
		{
			CMorphologicalProc::GetSingleton()->minkowski_opening(myModel,size);
		}
		else if (2 == iFlag)
		{//just erosion
			CMorphologicalProc::GetSingleton()->ReversMinKowskisum(myModel,size);
		}
	}
	//if (myModel)
	//{
	//	int Solid_no = 0;
	//	SOLID_itr solid_itr = myModel->begin();
	//	while (solid_itr != myModel->end())
	//	{
	//		SolidOBJ* solid = *solid_itr++;
	//		if (solid->Solid_mesh->size_of_vertices() == 0 || !solid->Solid_mesh->is_closed())
	//		{
	//			//CGAL_assertion(0);
	//			continue;
	//		}
	//		Nef_polyhedron_3* result = new Nef_polyhedron_3(*(solid->Solid_mesh));
	//		if (!result)
	//		{
	//			return false;
	//		}

	//		if (0 == iFlag)
	//		{//just closing
	//			std::cout<<"closing Solid:"<<Solid_no++<<std::endl;
	//			result = MinKowskisum(result,size);
	//			result = ReversMinKowskisum(result,size);
	//		}
	//		else if (1 == iFlag)
	//		{
	//			std::cout<<"openning Solid:"<<Solid_no++<<std::endl;
	//			result = ReversMinKowskisum(result,size);
	//			result = MinKowskisum(result,size);
	//		}
	//		else if (2 == iFlag)
	//		{//just opening
	//			std::cout<<"eliminateing Solid:"<<Solid_no++<<std::endl;
	//			result = ReversMinKowskisum(result,size);
	//			if (result->number_of_facets()!=0)
	//			{
	//				continue;
	//				delete result;
	//				result = NULL;
	//			}
	//		}
	//		//
	//		if (result->is_simple())
	//		{
	//			result->convert_to_polyhedron(*(solid->Solid_mesh));
	//		}
	//		else
	//		{
	//			std::cerr<<"minkowIKi diff cause non-2-manifold case"<<std::endl;
	//		}
	//		//
	//		delete result;
	//		result = NULL;
	//	}
	//}
	//else 
	//{
	//return false;
	//}
	return true;
}

void CGeneralizationAPI::do_Selection()
{
	Parser_obj* parser = Parser_obj::GetSingleton();
	//input
	char name[100];
	std::cout<<"name"<<std::endl;
	std::cin>>name;
	float size = 0.0;
	std::cout<<"size/scale:"<<std::endl;
	std::cin>>size;
	//float fTol = -1.0;
	//std::cout<<"fTol:"<<std::endl;
	//std::cin>>fTol;
	//int bType = 0;//tougong
	//std::cout<<"Tougong 1 Wa 0:"<<std::endl;
	//std::cin>>bType;
	ModelOBJ* myModel = new ModelOBJ;
	std::string objname(TESTOBJPATH);
	objname += name;
	std::string mtlname = objname + ".mtl";
	objname += ".obj";//Objname
	parser->read_model_obj(objname.c_str(),mtlname.c_str(),myModel);
	//write the process here
	//std::cout<<"simplify co-planer vertices: "<<Simplify_func::GetSingleton()->merge_coplaner_facets(myModel, NORMAL_DIF_TOL)<<std::endl;
	//opening
	float tempsize = size;
	std::cout<<"---->STEP1 elimination with the size of "<<tempsize<<std::endl;
	do_post_proc(myModel,tempsize,2/*elimination*/);
	//std::cout<<"simplify co-planer vertices: "<<Simplify_func::GetSingleton()->merge_coplaner_facets(myModel, NORMAL_DIF_TOL)<<std::endl;
	//closing
	tempsize = size*100;
	std::cout<<"---->STEP2 closing with the size of "<<tempsize<<std::endl;
	do_post_proc(myModel,tempsize,0/*closing*/);
	//std::cout<<"simplify co-planer vertices: "<<Simplify_func::GetSingleton()->merge_coplaner_facets(myModel, NORMAL_DIF_TOL)<<std::endl;
	////aggregation
	//std::cout<<"---->STEP3 aggregation"<<std::endl;
	//Polyhedron_3* poly = do_aggregation(myModel);
	//if (poly == NULL)
	//{
	//	return;
	//}
	ModelOBJ* myNewModel = new ModelOBJ;
	//SolidOBJ* myNewSolid = new SolidOBJ;
	//myNewSolid->Solid_mesh = poly;
	//myNewSolid->Solid_name = name;
	//myNewModel->push_back(myNewSolid);
	////
	//myModel->clear();
	//delete myModel;
	//myModel = NULL;
	//std::cout<<"simplify co-planer vertices: "<<Simplify_func::GetSingleton()->merge_coplaner_facets(myNewModel, NORMAL_DIF_TOL)<<std::endl;
	////closing
	//tempsize = size;
	//std::cout<<"---->STEP4 closing with the size of "<<tempsize<<std::endl;
	//do_post_proc(myNewModel,tempsize,1/*openning*/);
	//std::cout<<"simplify co-planer vertices: "<<Simplify_func::GetSingleton()->merge_coplaner_facets(myNewModel, NORMAL_DIF_TOL)<<std::endl;
	//
	myNewModel = myModel;
	//simplification of models
	std::cout<<"simplify co-planer vertices: "<<Simplify_func::GetSingleton()->merge_coplaner_facets(myNewModel, NORMAL_DIF_TOL)<<std::endl;
	if (myNewModel->empty())
	{
		return;
	}
	//output
	std::cout<<"---->STEP6 output"<<std::endl;
	std::string test2 = objname;
	std::string::size_type idx = test2.rfind('.');
	std::string tmpname = test2.substr(0,idx);
	tmpname += "_";
	std::stringstream ss;
	ss<<size;
	tmpname += ss.str();
	tmpname += ".obj";
	parser->write_obj(tmpname.c_str(),myNewModel);
	//
	if (myNewModel)
	{
		SOLID_itr solid_itr = myNewModel->begin();
		while(solid_itr != myNewModel->end())
		{
			SolidOBJ* curS = *solid_itr++;
			if (curS)
			{
				delete curS;
				curS = NULL;
			}
		}
		myNewModel->clear();
		delete myNewModel;
		myNewModel = NULL;
	}
}